package net.risesoft.api.permission;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.springframework.context.annotation.Primary;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;

import net.risesoft.entity.identity.Y9IdentityToResourceAndAuthorityBase;
import net.risesoft.entity.identity.position.Y9PositionToResourceAndAuthority;
import net.risesoft.enums.AuthorityEnum;
import net.risesoft.enums.ResourceTypeEnum;
import net.risesoft.model.Resource;
import net.risesoft.service.identity.Y9PositionToResourceAndAuthorityService;
import net.risesoft.y9.Y9LoginUserHolder;
import net.risesoft.y9.util.Y9ModelConvertUtil;
import net.risesoft.y9public.entity.resource.Y9Menu;
import net.risesoft.y9public.entity.resource.Y9ResourceBase;
import net.risesoft.y9public.manager.Y9ResourceBaseManager;
import net.risesoft.y9public.service.resource.Y9MenuService;

/**
 * 岗位资源权限组件
 *
 * @author dingzhaojun
 * @author qinman
 * @author mengjuhua
 * @date 2022/2/10
 * @since 9.6.0
 */
@Primary
@RestController
@RequestMapping(value = "/services/rest/positionResource", produces = MediaType.APPLICATION_JSON_VALUE)
@RequiredArgsConstructor
public class PositionResourceApiImpl implements PositionResourceApi {
    
    private final Y9ResourceBaseManager y9ResourceBaseManager;
    private final Y9MenuService y9MenuService;
    private final Y9PositionToResourceAndAuthorityService y9PositionToResourceAndAuthorityService;

    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }
    
    /**
     * 判断岗位对资源是否有指定的操作权限
     *
     * @param tenantId 租户id
     * @param positionId 操作者唯一标识
     * @param resourceId 资源唯一标识
     * @param authority 操作类型 {@link AuthorityEnum}
     * @return Boolean 是否有权限
     * @since 9.6.0
     */
    @Override
    @GetMapping("/hasPermission")
    public boolean hasPermission(@RequestParam String tenantId, @RequestParam String positionId, @RequestParam String resourceId, @RequestParam Integer authority) {
        Y9LoginUserHolder.setTenantId(tenantId);
        return y9PositionToResourceAndAuthorityService.hasPermission(positionId, resourceId, authority);
    }

    /**
     * 判断岗位对 customId 对应的资源是否有指定的操作权限
     *
     * @param tenantId 租户id
     * @param positionId 岗位id
     * @param customId 自定义id
     * @param authority 操作类型 {@link AuthorityEnum}
     * @return boolean
     * @since 9.6.0
     */
    @Override
    @GetMapping("/hasPermissionByCustomId")
    public boolean hasPermissionByCustomId(String tenantId, String positionId, String customId, Integer authority) {
        Y9LoginUserHolder.setTenantId(tenantId);
        return y9PositionToResourceAndAuthorityService.hasPermissionByCustomId(positionId, customId, authority);
    }

    /**
     * 获得某一资源下,主体对象有相应操作权限的子菜单
     *
     * @param tenantId 租户id
     * @param positionId 操作者唯一标识
     * @param authority 操作类型 {@link AuthorityEnum}
     * @param resourceId 资源唯一标识
     * @return List&lt;Resource&gt; 有操作权限的子菜单
     * @since 9.6.0
     */
    @Override
    @GetMapping("/listSubMenus")
    public List<Resource> listSubMenus(@RequestParam String tenantId, @RequestParam String positionId, @RequestParam Integer authority, @RequestParam String resourceId) {
        Y9LoginUserHolder.setTenantId(tenantId);
        Integer resourceType = ResourceTypeEnum.MENU.getValue();
        List<Y9PositionToResourceAndAuthority> personToResourceAndAuthorityList = y9PositionToResourceAndAuthorityService.list(positionId, resourceId, resourceType, authority);
        Set<String> menuIdList = personToResourceAndAuthorityList.stream().map(Y9IdentityToResourceAndAuthorityBase::getResourceId).collect(Collectors.toSet());

        List<Resource> resourceList = new ArrayList<>();
        for (String menuId : menuIdList) {
            Y9Menu y9Menu = y9MenuService.getById(menuId);
            if (y9Menu != null) {
                resourceList.add(Y9ModelConvertUtil.convert(y9Menu, Resource.class));
            }
        }
        return resourceList;
    }

    /**
     * 获得某一资源下,主体对象有相应操作权限的子节点
     *
     * @param tenantId 租户id
     * @param positionId 操作者唯一标识
     * @param authority 操作类型 {@link AuthorityEnum}
     * @param resourceId 资源唯一标识
     * @return List&lt;Resource&gt; 有操作权限的子节点
     * @since 9.6.0
     */
    @Override
    @GetMapping("/listSubResources")
    public List<Resource> listSubResources(@RequestParam String tenantId, @RequestParam String positionId, @RequestParam Integer authority, @RequestParam(required = false) String resourceId) {
        Y9LoginUserHolder.setTenantId(tenantId);
        List<Resource> returnResourceList = new ArrayList<>();

        List<Y9PositionToResourceAndAuthority> personToResourceAndAuthorityList = y9PositionToResourceAndAuthorityService.list(positionId, resourceId, authority);
        personToResourceAndAuthorityList = personToResourceAndAuthorityList.stream().filter(distinctByKey(Y9IdentityToResourceAndAuthorityBase::getResourceId)).collect(Collectors.toList());
        for (Y9PositionToResourceAndAuthority personResource : personToResourceAndAuthorityList) {
            Y9ResourceBase y9ResourceBase = y9ResourceBaseManager.findByIdAndResourceType(personResource.getResourceId(), personResource.getResourceType());
            if (y9ResourceBase != null) {
                returnResourceList.add(Y9ModelConvertUtil.convert(y9ResourceBase, Resource.class));
            }
        }
        return returnResourceList;
    }
}
